package net.kleinhenz.norabase.server.datasource;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;

import net.kleinhenz.norabase.client.datasource.EquipmentDSService;
import net.kleinhenz.norabase.server.BattlegroupServiceImpl;
import net.kleinhenz.norabase.server.BeanHelper;
import net.kleinhenz.norabase.server.EMF;
import net.kleinhenz.norabase.server.PoxNoraXMLReader;
import net.kleinhenz.norabase.server.model.Account;
import net.kleinhenz.norabase.server.model.RuneEntry;
import net.kleinhenz.norabase.shared.SortOrientation;
import net.kleinhenz.norabase.shared.TextMatchStyle;
import net.kleinhenz.norabase.shared.model.Equipment;
import net.kleinhenz.norabase.shared.model.FetchResult;
import net.kleinhenz.norabase.shared.model.Rune;

public class EquipmentDSServiceImpl extends RemoteServiceServlet implements EquipmentDSService {

	private static final long serialVersionUID = 1L;

    static int id;

	@Override
	public FetchResult<Equipment> fetch(final int start, final int end,
			final Map<String, SortOrientation> sortSpec,
			final TextMatchStyle textMatchStyle, 
			final Map<String, Object> criteria) {

		List<Equipment> result = new ArrayList<Equipment>();
		result.addAll(PoxNoraXMLReader.getEquipments());
		
		// filtering
		List<Equipment> toRemove = new ArrayList<Equipment>();
		for (Equipment c : result) {
			try {
				for (Map.Entry<String, Object> ce : criteria.entrySet()) {
					Object cVal = BeanHelper.getPropertyValue(c, ce.getKey());
					Object ceVal = ce.getValue();
					
					if (cVal instanceof Integer && ceVal instanceof Integer && ((Integer)cVal).intValue()!=((Integer)ceVal).intValue())
						toRemove.add(c);
					// FIXME Booolean cVal XOR ceVal -> remove
					else if (cVal instanceof String && ceVal instanceof String) {
						if (TextMatchStyle.EXACT.equals(textMatchStyle) && cVal!=null && !(((String)cVal).equals((String)ceVal)))
							toRemove.add(c);
						else if (TextMatchStyle.SUBSTRING.equals(textMatchStyle) && cVal!=null && !(((String)cVal).contains((String)ceVal)))
							toRemove.add(c);
					}
				}
			} catch (Exception e) {
				toRemove.add(c);
			}
		}
		result.removeAll(toRemove);

		// sorting
		if (sortSpec!=null)
			Collections.sort(result, new Comparator<Equipment>() {
				@Override
				public int compare(Equipment o1, Equipment o2) {

				    /* Should return:
				     * o1>o2 1
				     * o1<o2 -1
				     * o1=o2 0
				     */
					int order = 0;
					for (Map.Entry<String, SortOrientation> se : sortSpec.entrySet()) {

						try {
							Object value1 = BeanHelper.getPropertyValue(o1, se.getKey());
							Object value2 = BeanHelper.getPropertyValue(o2, se.getKey());
							if (value1 instanceof Integer && value2 instanceof Integer) {
								if ((Integer)value1<(Integer)value2)
									order=-1;
								else if ((Integer)value2>(Integer)value1)
									order=1;
							} else 	if (value1 instanceof Double && value2 instanceof Double) {
								if ((Double)value1<(Double)value2)
									order=-1;
								else if ((Double)value2>(Double)value1)
									order=1;
	
							} else if (value1 instanceof String && value2 instanceof String) {
								order=((String)value2).compareTo((String)value1);
							}
							if (SortOrientation.DESCENDING.equals(se.getValue()))
								order*=-1;
						} catch (Exception e) {
							return 0;
						}
					}
					return order;
				}
			});

		// truncating - sublist not working, serialization problems
		FetchResult<Equipment> finalResult = new FetchResult<Equipment>();
		finalResult.fullSize = result.size();
		for (int n = start; n<(end>result.size()?result.size():end); n++)
			finalResult.add(result.get(n));
		
		// add count to runes
		EntityManager em = EMF.get().createEntityManager();
		List<RuneEntry> runes = BattlegroupServiceImpl.retrieveAccount(em).getRunes();
		for (Rune r : finalResult) { 
			RuneEntry tE = RuneEntry.search(r.getId(), runes);
			if (tE!=null)
				r.setOwned(tE.getCount());
		}

		return finalResult;
	}
	
	@Override
	public Equipment update(Equipment record) {

		EntityManager em = EMF.get().createEntityManager();
		Account account = BattlegroupServiceImpl.retrieveAccount(em);

		RuneEntry re = new RuneEntry(record.getId(), Rune.EQUIPMENT);
		re.setCount(record.getOwned());
		List<RuneEntry> runes = account.getRunes();
		int index = -1;
		if ((index=runes.indexOf(re))==-1) {
			runes.add(re);
			em.persist(re);
		}
		else
			runes.get(index).setCount(record.getOwned());
		em.merge(account);
		em.close();
		return record;
	}	
}
